//******************************************************************************
//this code is protected by the GNU affero GPLv3
//author:Sylvain BERTRAND <sylvain.bertrand AT gmail dot com>
//                        <digital.ragnarok AT gmail dot com>
//******************************************************************************
#include "globals.h"

#define LOCAL_ERR(fmt,...) \
{\
void *sysname=(void*)udev_device_get_sysname(\
registry[c->output_name].output.d);\
PERR("cfg:output:%s:match:" fmt,sysname,##__VA_ARGS__);\
}

#define LOCAL_LOG(fmt,...) \
{\
void *sysname=(void*)udev_device_get_sysname(\
registry[c->output_name].output.d);\
LOG("cfg:output:%s:match:" fmt,sysname,##__VA_ARGS__);\
}

#if LOG_CFG_LVL>=2
#define LOCAL_LOG_LVL2(fmt,...) LOCAL_LOG(fmt,##__VA_ARGS__);
#else
#define LOCAL_LOG_LVL2 (void)0;
#endif

static void defaults(struct cfg_output_match_info *info)
{
  memset(&info->manufacturer_glob[0],0,
                                      CFG_OUTPUT_MATCH_MANUFACTURER_GLOB_MAX+1);
  memset(&info->product_code_glob[0],0,
                                      CFG_OUTPUT_MATCH_PRODUCT_CODE_GLOB_MAX+1);
  memset(&info->monitor_name_glob[0],0,
                                      CFG_OUTPUT_MATCH_MONITOR_NAME_GLOB_MAX+1);
  memset(&info->monitor_serial_glob[0],0,
                                    CFG_OUTPUT_MATCH_MONITOR_SERIAL_GLOB_MAX+1);
}

static void glob_get(void *name,u64 sz_max,void *d,struct cfg_ctx_output *c,
                                                     s64 val_start,s64 line_end)
{
  LOCAL_LOG_LVL2("%s glob key/value found\n",name);

  u64 glob_sz=line_end-val_start;
  if(glob_sz>sz_max){
    glob_sz=sz_max;
    LOCAL_ERR("warning:%s glob truncated\n",name);
  }
  strncpy(d,c->c.m+val_start,glob_sz);
}

static void manufacturer_glob_get(void *d,struct cfg_ctx_output *c,
                                                     s64 val_start,s64 line_end)
{
  glob_get("manufacturer",CFG_OUTPUT_MATCH_MANUFACTURER_GLOB_MAX,d,c,val_start,
                                                                      line_end);
}

static void product_code_glob_get(void *d,struct cfg_ctx_output *c,
                                                     s64 val_start,s64 line_end)
{
  glob_get("product code",CFG_OUTPUT_MATCH_PRODUCT_CODE_GLOB_MAX,d,c,val_start,
                                                                      line_end);
}

static void monitor_name_glob_get(void *d,struct cfg_ctx_output *c,
                                                     s64 val_start,s64 line_end)
{
  glob_get("monitor name",CFG_OUTPUT_MATCH_MONITOR_NAME_GLOB_MAX,d,c,val_start,
                                                                      line_end);
}

static void monitor_serial_glob_get(void *d,struct cfg_ctx_output *c,
                                                     s64 val_start,s64 line_end)
{
  glob_get("monitor serial",CFG_OUTPUT_MATCH_MONITOR_SERIAL_GLOB_MAX,d,c,
                                                            val_start,line_end);
}

#if LOG_CFG_LVL>=2
#define LOCAL_LOG_LVL2_DUMP_LINE \
{\
u8 line_buf[129];\
memset(&line_buf[0],0,129);\
u8 sz=line_end-line_start;\
memcpy(&line_buf[0],c->c.m+line_start,sz>128?128:sz);\
LOCAL_LOG("%ld \"%s\"\n",line_start,&line_buf[0]);\
}
#else
#define LOCAL_LOG_LVL2_DUMP_LINE
#endif

#define MANUFACTURER_GLOB_KEY_STR "manufacturer_glob"
#define PRODUCT_CODE_GLOB_KEY_STR "product_code_glob"
#define MONITOR_NAME_GLOB_KEY_STR "monitor_name_glob"
#define MONITOR_SERIAL_GLOB_KEY_STR "monitor_serial_glob"

#define IS_KEY(x) (val_start-1-key_start)==cs_n(x ## _KEY_STR)\
&&!strncmp(c->c.m+key_start,x ## _KEY_STR,val_start-1-key_start)
void cfg_output_match_info_get(struct cfg_ctx_output *c,s64 output_start,
                                             struct cfg_output_match_info *info)
{
  defaults(info);

  s64 line_start=output_start;
  while(1){
    if((u64)line_start>=c->c.sz){
      LOCAL_LOG_LVL2("no more misc key/value:line start not in file\n");
      break;
    }

    s64 line_end=cfg_line_end_reach(&c->c,line_start);
    LOCAL_LOG_LVL2_DUMP_LINE;

    s64 key_start=cfg_blanks_skip(&c->c,line_start,line_end);

    //finished:beginning of next section reached ("[key]")
    if(*(u8*)(c->c.m+key_start)=='[') break;

    s64 val_start=cfg_key_skip_to_val(&c->c,key_start,line_end);
    if(val_start==CFG_KEY_SKIP_TO_VAL_NO_VAL){
      LOCAL_LOG_LVL2("no value\n");
    }else{
      if(IS_KEY(MANUFACTURER_GLOB))
        manufacturer_glob_get(&info->manufacturer_glob[0],c,val_start,line_end);
      else if(IS_KEY(PRODUCT_CODE_GLOB)) 
        product_code_glob_get(&info->product_code_glob[0],c,val_start,line_end);
      else if(IS_KEY(MONITOR_NAME_GLOB)) 
        monitor_name_glob_get(&info->monitor_name_glob[0],c,val_start,line_end);
      else if(IS_KEY(MONITOR_SERIAL_GLOB)) 
        monitor_serial_glob_get(&info->monitor_serial_glob[0],c,val_start,
                                                                      line_end);
    }

    line_start=line_end+1;
  }
  LOCAL_LOG("manufacturer_glob='%s' product_code_glob='%s'"
                             " monitor_name_glob='%s' monitor_serial_glob=%s\n",
                             &info->manufacturer_glob[0],
                             &info->product_code_glob[0],
                             &info->monitor_name_glob[0],
                             &info->monitor_serial_glob[0]);
}
